home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65 / src / alias.c next >
Encoding:
C/C++ Source or Header  |  1990-06-05  |  11.7 KB  |  583 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. #ifdef DBM
  23. static char sccsid[] = "@(#)alias.c    5.21 (Berkeley) 6/1/90 (with DBM)";
  24. #else
  25. static char sccsid[] = "@(#)alias.c    5.21 (Berkeley) 6/1/90 (without DBM)";
  26. #endif
  27. #endif /* not lint */
  28.  
  29. # include <sys/types.h>
  30. # include <sys/stat.h>
  31. # include <signal.h>
  32. # include <errno.h>
  33. # include "sendmail.h"
  34. # include <sys/file.h>
  35. # include <pwd.h>
  36.  
  37. /*
  38. **  ALIAS -- Compute aliases.
  39. **
  40. **    Scans the alias file for an alias for the given address.
  41. **    If found, it arranges to deliver to the alias list instead.
  42. **    Uses libdbm database if -DDBM.
  43. **
  44. **    Parameters:
  45. **        a -- address to alias.
  46. **        sendq -- a pointer to the head of the send queue
  47. **            to put the aliases in.
  48. **
  49. **    Returns:
  50. **        none
  51. **
  52. **    Side Effects:
  53. **        Aliases found are expanded.
  54. **
  55. **    Notes:
  56. **        If NoAlias (the "-n" flag) is set, no aliasing is
  57. **            done.
  58. **
  59. **    Deficiencies:
  60. **        It should complain about names that are aliased to
  61. **            nothing.
  62. */
  63.  
  64.  
  65. #ifdef DBM
  66. typedef struct
  67. {
  68.     char    *dptr;
  69.     int    dsize;
  70. } DATUM;
  71. extern DATUM fetch();
  72. #endif DBM
  73.  
  74. alias(a, sendq)
  75.     register ADDRESS *a;
  76.     ADDRESS **sendq;
  77. {
  78.     register char *p;
  79.     extern char *aliaslookup();
  80.  
  81.     if (tTd(27, 1))
  82.         printf("alias(%s)\n", a->q_paddr);
  83.  
  84.     /* don't realias already aliased names */
  85.     if (bitset(QDONTSEND, a->q_flags))
  86.         return;
  87.  
  88.     CurEnv->e_to = a->q_paddr;
  89.  
  90.     /*
  91.     **  Look up this name
  92.     */
  93.  
  94.     if (NoAlias)
  95.         p = NULL;
  96.     else
  97.         p = aliaslookup(a->q_user);
  98.     if (p == NULL)
  99.         return;
  100.  
  101.     /*
  102.     **  Match on Alias.
  103.     **    Deliver to the target list.
  104.     */
  105.  
  106.     if (tTd(27, 1))
  107.         printf("%s (%s, %s) aliased to %s\n",
  108.             a->q_paddr, a->q_host, a->q_user, p);
  109.     message(Arpa_Info, "aliased to %s", p);
  110.     AliasLevel++;
  111.     sendtolist(p, a, sendq);
  112.     AliasLevel--;
  113. }
  114. /*
  115. **  ALIASLOOKUP -- look up a name in the alias file.
  116. **
  117. **    Parameters:
  118. **        name -- the name to look up.
  119. **
  120. **    Returns:
  121. **        the value of name.
  122. **        NULL if unknown.
  123. **
  124. **    Side Effects:
  125. **        none.
  126. **
  127. **    Warnings:
  128. **        The return value will be trashed across calls.
  129. */
  130.  
  131. char *
  132. aliaslookup(name)
  133.     char *name;
  134. {
  135. # ifdef DBM
  136.     DATUM rhs, lhs;
  137.  
  138.     /* create a key for fetch */
  139.     lhs.dptr = name;
  140.     lhs.dsize = strlen(name) + 1;
  141.     rhs = fetch(lhs);
  142.     return (rhs.dptr);
  143. # else DBM
  144.     register STAB *s;
  145.  
  146.     s = stab(name, ST_ALIAS, ST_FIND);
  147.     if (s == NULL)
  148.         return (NULL);
  149.     return (s->s_alias);
  150. # endif DBM
  151. }
  152. /*
  153. **  INITALIASES -- initialize for aliasing
  154. **
  155. **    Very different depending on whether we are running DBM or not.
  156. **
  157. **    Parameters:
  158. **        aliasfile -- location of aliases.
  159. **        init -- if set and if DBM, initialize the DBM files.
  160. **
  161. **    Returns:
  162. **        none.
  163. **
  164. **    Side Effects:
  165. **        initializes aliases:
  166. **        if DBM:  opens the database.
  167. **        if ~DBM: reads the aliases into the symbol table.
  168. */
  169.  
  170. # define DBMMODE    0644
  171.  
  172. initaliases(aliasfile, init)
  173.     char *aliasfile;
  174.     bool init;
  175. {
  176. #ifdef DBM
  177.     int atcnt;
  178.     time_t modtime;
  179.     bool automatic = FALSE;
  180.     char buf[MAXNAME];
  181. #endif DBM
  182.     struct stat stb;
  183.     static bool initialized = FALSE;
  184.  
  185.     if (initialized)
  186.         return;
  187.     initialized = TRUE;
  188.  
  189.     if (aliasfile == NULL || stat(aliasfile, &stb) < 0)
  190.     {
  191.         if (aliasfile != NULL && init)
  192.             syserr("Cannot open %s", aliasfile);
  193.         NoAlias = TRUE;
  194.         errno = 0;
  195.         return;
  196.     }
  197.  
  198. # ifdef DBM
  199.     /*
  200.     **  Check to see that the alias file is complete.
  201.     **    If not, we will assume that someone died, and it is up
  202.     **    to us to rebuild it.
  203.     */
  204.  
  205.     if (!init)
  206.         dbminit(aliasfile);
  207.     atcnt = SafeAlias * 2;
  208.     if (atcnt > 0)
  209.     {
  210.         while (!init && atcnt-- >= 0 && aliaslookup("@") == NULL)
  211.         {
  212.             /*
  213.             **  Reinitialize alias file in case the new
  214.             **  one is mv'ed in instead of cp'ed in.
  215.             **
  216.             **    Only works with new DBM -- old one will
  217.             **    just consume file descriptors forever.
  218.             **    If you have a dbmclose() it can be
  219.             **    added before the sleep(30).
  220.             */
  221.  
  222.             sleep(30);
  223. # ifdef NDBM
  224.             dbminit(aliasfile);
  225. # endif NDBM
  226.         }
  227.     }
  228.     else
  229.         atcnt = 1;
  230.  
  231.     /*
  232.     **  See if the DBM version of the file is out of date with
  233.     **  the text version.  If so, go into 'init' mode automatically.
  234.     **    This only happens if our effective userid owns the DBM.
  235.     **    Note the unpalatable hack to see if the stat succeeded.
  236.     */
  237.  
  238.     modtime = stb.st_mtime;
  239.     (void) strcpy(buf, aliasfile);
  240.     (void) strcat(buf, ".pag");
  241.     stb.st_ino = 0;
  242.     if (!init && (stat(buf, &stb) < 0 || stb.st_mtime < modtime || atcnt < 0))
  243.     {
  244.         errno = 0;
  245.         if (AutoRebuild && stb.st_ino != 0 && stb.st_uid == geteuid())
  246.         {
  247.             init = TRUE;
  248.             automatic = TRUE;
  249.             message(Arpa_Info, "rebuilding alias database");
  250. #ifdef LOG
  251.             if (LogLevel >= 7)
  252.                 syslog(LOG_INFO, "rebuilding alias database");
  253. #endif LOG
  254.         }
  255.         else
  256.         {
  257. #ifdef LOG
  258.             if (LogLevel >= 7)
  259.                 syslog(LOG_INFO, "alias database out of date");
  260. #endif LOG
  261.             message(Arpa_Info, "Warning: alias database out of date");
  262.         }
  263.     }
  264.  
  265.  
  266.     /*
  267.     **  If necessary, load the DBM file.
  268.     **    If running without DBM, load the symbol table.
  269.     */
  270.  
  271.     if (init)
  272.     {
  273. #ifdef LOG
  274.         if (LogLevel >= 6)
  275.         {
  276.             extern char *username();
  277.  
  278.             syslog(LOG_NOTICE, "alias database %srebuilt by %s",
  279.                 automatic ? "auto" : "", username());
  280.         }
  281. #endif LOG
  282.         readaliases(aliasfile, TRUE);
  283.     }
  284. # else DBM
  285.     readaliases(aliasfile, init);
  286. # endif DBM
  287. }
  288. /*
  289. **  READALIASES -- read and process the alias file.
  290. **
  291. **    This routine implements the part of initaliases that occurs
  292. **    when we are not going to use the DBM stuff.
  293. **
  294. **    Parameters:
  295. **        aliasfile -- the pathname of the alias file master.
  296. **        init -- if set, initialize the DBM stuff.
  297. **
  298. **    Returns:
  299. **        none.
  300. **
  301. **    Side Effects:
  302. **        Reads aliasfile into the symbol table.
  303. **        Optionally, builds the .dir & .pag files.
  304. */
  305.  
  306. static
  307. readaliases(aliasfile, init)
  308.     char *aliasfile;
  309.     bool init;
  310. {
  311.     register char *p;
  312.     char *rhs;
  313.     bool skipping;
  314.     int naliases, bytes, longest;
  315.     FILE *af;
  316.     void (*oldsigint)();
  317.     ADDRESS al, bl;
  318.     register STAB *s;
  319.     char line[BUFSIZ];
  320.  
  321.     if ((af = fopen(aliasfile, "r")) == NULL)
  322.     {
  323.         if (tTd(27, 1))
  324.             printf("Can't open %s\n", aliasfile);
  325.         errno = 0;
  326.         NoAlias++;
  327.         return;
  328.     }
  329.  
  330. # ifdef DBM
  331.     /* see if someone else is rebuilding the alias file already */
  332.     if (flock(fileno(af), LOCK_EX | LOCK_NB) < 0 && errno == EWOULDBLOCK)
  333.     {
  334.         /* yes, they are -- wait until done and then return */
  335.         message(Arpa_Info, "Alias file is already being rebuilt");
  336.         if (OpMode != MD_INITALIAS)
  337.         {
  338.             /* wait for other rebuild to complete */
  339.             (void) flock(fileno(af), LOCK_EX);
  340.         }
  341.         (void) fclose(af);
  342.         errno = 0;
  343.         return;
  344.     }
  345. # endif DBM
  346.  
  347.     /*
  348.     **  If initializing, create the new DBM files.
  349.     */
  350.  
  351.     if (init)
  352.     {
  353.         oldsigint = signal(SIGINT, SIG_IGN);
  354.         (void) strcpy(line, aliasfile);
  355.         (void) strcat(line, ".dir");
  356.         if (close(creat(line, DBMMODE)) < 0)
  357.         {
  358.             syserr("cannot make %s", line);
  359.             (void) signal(SIGINT, oldsigint);
  360.             return;
  361.         }
  362.         (void) strcpy(line, aliasfile);
  363.         (void) strcat(line, ".pag");
  364.         if (close(creat(line, DBMMODE)) < 0)
  365.         {
  366.             syserr("cannot make %s", line);
  367.             (void) signal(SIGINT, oldsigint);
  368.             return;
  369.         }
  370.         dbminit(aliasfile);
  371.     }
  372.  
  373.     /*
  374.     **  Read and interpret lines
  375.     */
  376.  
  377.     FileName = aliasfile;
  378.     LineNumber = 0;
  379.     naliases = bytes = longest = 0;
  380.     skipping = FALSE;
  381.     while (fgets(line, sizeof (line), af) != NULL)
  382.     {
  383.         int lhssize, rhssize;
  384.  
  385.         LineNumber++;
  386.         p = index(line, '\n');
  387.         if (p != NULL)
  388.             *p = '\0';
  389.         switch (line[0])
  390.         {
  391.           case '#':
  392.           case '\0':
  393.             skipping = FALSE;
  394.             continue;
  395.  
  396.           case ' ':
  397.           case '\t':
  398.             if (!skipping)
  399.                 syserr("Non-continuation line starts with space");
  400.             skipping = TRUE;
  401.             continue;
  402.         }
  403.         skipping = FALSE;
  404.  
  405.         /*
  406.         **  Process the LHS
  407.         **    Find the final colon, and parse the address.
  408.         **    It should resolve to a local name -- this will
  409.         **    be checked later (we want to optionally do
  410.         **    parsing of the RHS first to maximize error
  411.         **    detection).
  412.         */
  413.  
  414.         for (p = line; *p != '\0' && *p != ':' && *p != '\n'; p++)
  415.             continue;
  416.         if (*p++ != ':')
  417.         {
  418.             syserr("missing colon");
  419.             continue;
  420.         }
  421.         if (parseaddr(line, &al, 1, ':') == NULL)
  422.         {
  423.             syserr("illegal alias name");
  424.             continue;
  425.         }
  426.         loweraddr(&al);
  427.  
  428.         /*
  429.         **  Process the RHS.
  430.         **    'al' is the internal form of the LHS address.
  431.         **    'p' points to the text of the RHS.
  432.         */
  433.  
  434.         rhs = p;
  435.         for (;;)
  436.         {
  437.             register char c;
  438.  
  439.             if (init && CheckAliases)
  440.             {
  441.                 /* do parsing & compression of addresses */
  442.                 while (*p != '\0')
  443.                 {
  444.                     extern char *DelimChar;
  445.  
  446.                     while (isspace(*p) || *p == ',')
  447.                         p++;
  448.                     if (*p == '\0')
  449.                         break;
  450.                     if (parseaddr(p, &bl, -1, ',') == NULL)
  451.                         usrerr("%s... bad address", p);
  452.                     p = DelimChar;
  453.                 }
  454.             }
  455.             else
  456.             {
  457.                 p = &p[strlen(p)];
  458.                 if (p[-1] == '\n')
  459.                     *--p = '\0';
  460.             }
  461.  
  462.             /* see if there should be a continuation line */
  463.             c = fgetc(af);
  464.             if (!feof(af))
  465.                 (void) ungetc(c, af);
  466.             if (c != ' ' && c != '\t')
  467.                 break;
  468.  
  469.             /* read continuation line */
  470.             if (fgets(p, sizeof line - (p - line), af) == NULL)
  471.                 break;
  472.             LineNumber++;
  473.         }
  474.         if (al.q_mailer != LocalMailer)
  475.         {
  476.             syserr("cannot alias non-local names");
  477.             continue;
  478.         }
  479.  
  480.         /*
  481.         **  Insert alias into symbol table or DBM file
  482.         */
  483.  
  484.         lhssize = strlen(al.q_user) + 1;
  485.         rhssize = strlen(rhs) + 1;
  486.  
  487. # ifdef DBM
  488.         if (init)
  489.         {
  490.             DATUM key, content;
  491.  
  492.             key.dsize = lhssize;
  493.             key.dptr = al.q_user;
  494.             content.dsize = rhssize;
  495.             content.dptr = rhs;
  496.             store(key, content);
  497.         }
  498.         else
  499. # endif DBM
  500.         {
  501.             s = stab(al.q_user, ST_ALIAS, ST_ENTER);
  502.             s->s_alias = newstr(rhs);
  503.         }
  504.  
  505.         /* statistics */
  506.         naliases++;
  507.         bytes += lhssize + rhssize;
  508.         if (rhssize > longest)
  509.             longest = rhssize;
  510.     }
  511.  
  512. # ifdef DBM
  513.     if (init)
  514.     {
  515.         /* add the distinquished alias "@" */
  516.         DATUM key;
  517.  
  518.         key.dsize = 2;
  519.         key.dptr = "@";
  520.         store(key, key);
  521.  
  522.         /* restore the old signal */
  523.         (void) signal(SIGINT, oldsigint);
  524.     }
  525. # endif DBM
  526.  
  527.     /* closing the alias file drops the lock */
  528.     (void) fclose(af);
  529.     CurEnv->e_to = NULL;
  530.     FileName = NULL;
  531.     message(Arpa_Info, "%d aliases, longest %d bytes, %d bytes total",
  532.             naliases, longest, bytes);
  533. # ifdef LOG
  534.     if (LogLevel >= 8)
  535.         syslog(LOG_INFO, "%d aliases, longest %d bytes, %d bytes total",
  536.             naliases, longest, bytes);
  537. # endif LOG
  538. }
  539. /*
  540. **  FORWARD -- Try to forward mail
  541. **
  542. **    This is similar but not identical to aliasing.
  543. **
  544. **    Parameters:
  545. **        user -- the name of the user who's mail we would like
  546. **            to forward to.  It must have been verified --
  547. **            i.e., the q_home field must have been filled
  548. **            in.
  549. **        sendq -- a pointer to the head of the send queue to
  550. **            put this user's aliases in.
  551. **
  552. **    Returns:
  553. **        none.
  554. **
  555. **    Side Effects:
  556. **        New names are added to send queues.
  557. */
  558.  
  559. forward(user, sendq)
  560.     ADDRESS *user;
  561.     ADDRESS **sendq;
  562. {
  563.     char buf[60];
  564.     extern bool safefile();
  565.  
  566.     if (tTd(27, 1))
  567.         printf("forward(%s)\n", user->q_paddr);
  568.  
  569.     if (user->q_mailer != LocalMailer || bitset(QBADADDR, user->q_flags))
  570.         return;
  571.     if (user->q_home == NULL)
  572.         syserr("forward: no home");
  573.  
  574.     /* good address -- look for .forward file in home */
  575.     define('z', user->q_home, CurEnv);
  576.     expand("\001z/.forward", buf, &buf[sizeof buf - 1], CurEnv);
  577.     if (!safefile(buf, user->q_uid, S_IREAD))
  578.         return;
  579.  
  580.     /* we do have an address to forward to -- do it */
  581.     include(buf, "forwarding", user, sendq);
  582. }
  583.